package com.whfc.mach.manager.impl;

import com.whfc.common.exception.BizException;
import com.whfc.mach.dao.AppMachStrategyMapper;
import com.whfc.mach.dto.strategy.MachStrategyDTO;
import com.whfc.mach.manager.MachStrategyMgr;
import com.whfc.mach.manager.strategy.oil.DiffOilStrategy;
import com.whfc.mach.manager.strategy.oil.OilStrategy;
import com.whfc.mach.manager.strategy.work.DefaultWorkStrategy;
import com.whfc.mach.manager.strategy.work.WorkStrategy;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description:
 * @author: xugcheng
 * @version: 1.0
 * @date: 2020-12-14 11:50
 */
@Service
@DependsOn("liquibase")
public class MachStrategyMgrImpl implements MachStrategyMgr {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private static Map<Integer, Map<Integer, WorkStrategy>> workStrategyMap = new ConcurrentHashMap<>(10);

    private static Map<Integer, Map<Integer, OilStrategy>> oilStrategyMap = new ConcurrentHashMap<>(10);

    private static WorkStrategy DEFAULT_WORK_STRATEGY = new DefaultWorkStrategy();

    private static OilStrategy DEFAULT_OIL_STRATEGY = new DiffOilStrategy();

    @Autowired
    private AppMachStrategyMapper strategyMapper;

    @PostConstruct
    public void init() {
        try {
            List<MachStrategyDTO> strategyDTOList = strategyMapper.selectAllStrategy();
            if (strategyDTOList.size() > 0) {
                for (MachStrategyDTO strategyDTO : strategyDTOList) {
                    Integer deptId = strategyDTO.getDeptId();
                    Integer machType = strategyDTO.getMachType();
                    OilStrategy oilStrategy = this.getOilStrategy(strategyDTO.getOilStrategy());
                    WorkStrategy workStrategy = this.getWorkStrategy(strategyDTO.getWorkStrategy());
                    if (oilStrategy != null) {
                        Map<Integer, OilStrategy> deptOilStrategyMap = oilStrategyMap.get(deptId);
                        if (deptOilStrategyMap == null) {
                            deptOilStrategyMap = new ConcurrentHashMap<>(strategyDTOList.size());
                            oilStrategyMap.put(deptId, deptOilStrategyMap);
                        }
                        deptOilStrategyMap.put(machType, oilStrategy);
                    }
                    if (workStrategy != null) {
                        Map<Integer, WorkStrategy> deptWorkStrategyMap = workStrategyMap.get(deptId);
                        if (deptWorkStrategyMap == null) {
                            deptWorkStrategyMap = new ConcurrentHashMap<>(strategyDTOList.size());
                            workStrategyMap.put(deptId, deptWorkStrategyMap);
                        }
                        deptWorkStrategyMap.put(machType, workStrategy);
                    }
                }
            }
        } catch (Exception ex) {
            logger.error("", ex);
        }
    }

    @Override
    public void initStrategy(Integer deptId) throws BizException {
        List<MachStrategyDTO> strategyDTOList = strategyMapper.selectStrategyByDeptId(deptId);
        if (strategyDTOList.size() > 0) {
            Map<Integer, OilStrategy> deptOilStrategyMap = new ConcurrentHashMap<>(strategyDTOList.size());
            Map<Integer, WorkStrategy> deptWorkStrategyMap = new ConcurrentHashMap<>(strategyDTOList.size());
            for (MachStrategyDTO strategyDTO : strategyDTOList) {
                Integer machType = strategyDTO.getMachType();
                OilStrategy oilStrategy = this.getOilStrategy(strategyDTO.getOilStrategy());
                WorkStrategy workStrategy = this.getWorkStrategy(strategyDTO.getWorkStrategy());
                deptOilStrategyMap.put(machType, oilStrategy);
                deptWorkStrategyMap.put(machType, workStrategy);
            }
            workStrategyMap.put(deptId, deptWorkStrategyMap);
            oilStrategyMap.put(deptId, deptOilStrategyMap);
        }
    }

    @Override
    public List<MachStrategyDTO> getStrategy(Integer deptId) throws BizException {
        return strategyMapper.selectStrategyByDeptId(deptId);
    }

    @Override
    public MachStrategyDTO getStrategy(Integer deptId, Integer machType) throws BizException {
        return strategyMapper.selectStrategyByMachType(deptId, machType);
    }

    @Override
    public WorkStrategy getWorkStrategy(Integer deptId, Integer machType) throws BizException {
        if (workStrategyMap.containsKey(deptId)) {
            Map<Integer, WorkStrategy> strategyMap = workStrategyMap.get(deptId);
            if (strategyMap != null && strategyMap.containsKey(machType)) {
                return strategyMap.get(machType);
            }
        }
        return DEFAULT_WORK_STRATEGY;
    }

    @Override
    public OilStrategy getOilStrategy(Integer deptId, Integer machType) throws BizException {
        if (oilStrategyMap.containsKey(deptId)) {
            Map<Integer, OilStrategy> strategyMap = oilStrategyMap.get(deptId);
            if (strategyMap != null && strategyMap.containsKey(machType)) {
                return strategyMap.get(machType);
            }
        }
        return DEFAULT_OIL_STRATEGY;
    }

    /**
     * 根据名称获取工时策略
     *
     * @param workStrategyClassName
     * @return
     */
    private WorkStrategy getWorkStrategy(String workStrategyClassName) {

        //通过反射获取策略对象
        if (!StringUtils.isBlank(workStrategyClassName)) {
            try {
                WorkStrategy workStrategy = (WorkStrategy) Class.forName(workStrategyClassName).newInstance();
                return workStrategy;
            } catch (Exception ex) {
                logger.warn("无效的油量策略,{}", workStrategyClassName);
            }
        }
        return null;
    }

    /**
     * 根据名称获取油量策略
     *
     * @param oilStrategyClassName
     * @return
     */
    private OilStrategy getOilStrategy(String oilStrategyClassName) {
        //通过反射获取策略对象
        if (!StringUtils.isBlank(oilStrategyClassName)) {
            try {
                OilStrategy oilStrategy = (OilStrategy) Class.forName(oilStrategyClassName).newInstance();
                return oilStrategy;
            } catch (Exception ex) {
                logger.warn("无效的油量策略,{}", oilStrategyClassName);
            }
        }
        return null;
    }
}
